CBReno


iOSer 现在正在学习Kotlin写后台。。。


SwiftyJSON中文文档翻译

最近正在编写 iOS APP 的后台接口,调试的时候要解析JSON数据,所以就来学习使用 SwiftyJSON 这个第三方库,但网上搜的资料感觉写的都不怎么样,最后就只能硬着头皮看官方的文档了,尝试着翻译,借此机会学习并且提高一下自己的 English 水平吧。Let’s GO. (PS: 虽然官网也有中文翻译,但是好像不是很全。。。。。😆).如果有翻译错误❎,请见谅也请指出,谢谢!

SwiftyJSON 使得在 Swift 下处理 JSON 数据变得非常容易。

  1. 为什么在 Swift 下处理 JSON 数据的方式不是很好
  2. 需求
  3. 整合
  4. 用法
  5. 和 Alamofire 一起使用

为什么在 Swift 下处理 JSON 数据的方式不是很好

Swift 是一种严格的类型安全的语言。尽管明确的类型有利于我们减少错误,但是当我们在处理 JSON 和 其他隐式数据类型的时候就变得很痛苦。

拿 Twitter API 举个栗子。我将在 Swift 的下取回一个用户的 “名字”(根据 Twitter 的 API https://dev.twitter.com/docs/api/1.1/get/statuses/home_timeline)。

代码是这样子的:

1
2
3
4
5
if let statusesArray = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [[String: Any]],
let user = statusesArray[0]["user"] as? [String: Any],
let username = user["name"] as? String {
// Finally we got the username
}

这样不是很好。

即使我们使用可选绑定,看起来也是一团糟:

1
2
3
4
if let JSONObject = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [[String: Any]],
let username = (JSONObject[0]["user"] as? [String: Any])?["name"] as? String {
// There's our username
}

不可读的、一团糟。但是有些东西应该是简单的。

用 SwiftyJSON 你只需这么做:

1
2
3
4
let json = JSON(data: dataFromNetworking)
if let userName = json[0]["user"]["name"].string {
//now you got your value
}

并且你也不用担心可选类型拆包。这些都是自动帮你完成。

1
2
3
4
5
6
7
let json = JSON(data: dataFromNetworking)
if let userName = json[999999]["wrong_key"]["wrong_name"].string {
//calm down, take it easy. the ".string" property still produces the current Optional String type with safety
} else {
//print the error
print(json[999999]["wrong_ket"]["wrong_name"])
}

需求

  • iOS 8.0+ | macOS 10.10+|watch 2.0+

  • Xcode 8

整合

CocoaPods(iOS 8+, OS X 10.9+)

你可以使用 CocoaPods 来 安装 SwiftyJSON ,只要把一下的添加到 Podfile :

1
2
3
4
5
6
platform :iOS, '8.0'
use_frameworks!

target 'YourAPPName' do
pod 'SwiftyJSON'
end

注意这需要 CocoaPods 版本 36,并且你的 iOS 开发版本至少是 8.0:

Carthage(iOS 8+,OS X 10.9+)

你可以通过使用 Cathage 来安装 SwiftyJSON ,只需把一下的添加到 Cartfile:

1
github "SwiftyJOSN/SwiftyJSON"
Swift Package Manager

你可以使用 The Swift Package Manager 来安装 SwiftyJSON ,只需添加合适的描述到你的 Package.swift 文件:

1
2
3
4
5
6
7
8
9
import PackageDescription

let package = Package(
name: "YOUR_PROJECT_NAME",
targets: [],
dependencies: [
.Package(url: "https://github.com/SwiftyJSON/SwiftyJSON.git", versions: Version(1, 0, 0)..<Version(3, .max, .max)),
]
)

注意, Swift Package Manager 任然处于早期设计和开发阶段,更多信息请查看 GitHub Page

手动添加(iOS7+,OS X 10.9+)

为了在你的项目中使用这个库你通常需要:

  1. 对于单个项目,只需将 SwiftyJSON.swift 拖进你的项目
  2. 对于工作组,包含整个 SwiftyJSON.xcodeproj

用法

初始化
1
import SwiftyJSON
1
let json = JSON(data: dataFromNetworking)
1
let json = JSON(jsonobject)
1
2
3
if let dataFromString = jsonString.data(using: .utf8, allowLossyConversion: false) {
let json = JSON(data: dataFromString)
}
下标
1
2
//从 JSON数组 中获取一个 double
let name = json[0].double
1
2
//从一个 JSON数组 里获取一个 字符串数组
let arrayNames = json["users"].arrayValue.map({$0["name"].stringValue})
1
2
//从一个 JSON字典 中获取一个 string
let name = json["name"].stringValue
1
2
3
4
5
6
7
//通过元素的路径来获取 string
let path: [JSONSubscriptType] = [1, "list", 2, "name"]
let name = json[path].string
//同样的
let name = json[1]["list"][2]["name"].string
//或者
let name = json[1, "list", 2, "name"].string
1
2
//条件苛刻的情况
let name = json[].string
1
2
3
//普通的方法
let keys: [SubscriptType] = [1, "list", 2, "name"]
let name = json[keys].string
循环
1
2
3
4
//如果 JSON 是字典
for (key, subJson):(String, JSON) in json {
//做你想做的事情
}

即使 JSON 是数组,第一个元素也总是字符串。

1
2
3
4
5
//如果 JSON是数组
//index 是0到JSON数量的一个字符串值
for (index, subJson):(String, JSON) in json {
//做你想做的事情
}
错误

使用下标来获取或设置字典或数组里的一个值

如果 JSON 是:

  • 一个数组,应用可能奔溃由于数组越界。
  • 一个字典,它将返回 nil 并且没有原因。
  • 不是字典或者数组,应用可能因为“不认识选择器”而奔溃。

这些在 SwiftyJSON 中都不会发生。

1
2
3
4
5
6
let json = JSON(["name", "age"])
if let name = json[999].string {
//做你想做的事情
} else {
print(json[999].error)//"Array[999] 已经越界了"
}
1
2
3
4
5
6
let json = JSON(["name":"Jack", "age": 25])
if let name = json["address"].string {
//做你想做的事情
} else {
print(json["address"].error)//"Dictionary["address"]并不存在"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
let json = JSON(12345)
if let age = json[0].string {
//做你想做的事情
} else {
print(json[0]) // "Array[0] 失败,这不是一个数组"
print(json[0].error) // "Array[0] 失败, 这不是一个数组"
}

if let name = json["name"].string {
//做你想做的事情
} else {
print(json["name"]) //"Dictionary[\"name"] 失败, 这不是一个字典"
print(json["name"].error) //"Dictionary[\"name"] 失败,这不是一个字典"
}
Optional getter
1
2
3
4
5
6
7
//数字
if let id = json["user"]["favourites_count"].number {
//做你想做的事情
} else {
//打印错误
print(json["user"]["favourites_count"].error)
}
1
2
3
4
5
6
7
//字符串
if let id = json["user"]["name"].string {
//做你想做的事情
} else {
//打印错误
print(json["user"]["name"])
}
1
2
3
4
5
6
7
//bool
if let id = json["user"]["is_translator"].bool {
//做你想做的事情
} else {
//打印错误
print(json["user"]["is_translator"])
}
1
2
3
4
5
6
7
8
//整型
if let id = json["user"]["id"].int {
//做你想做的事情
} else {
//打印错误
print(json["user"]["id"])
}
...
Non-optional getter

非可选 getter 名为 xxxValue

1
2
//如果不是数字或者空,返回 0
let id : Int = json["id"].intValue
1
2
//如果不是字符串或者空,返回 ""
let name: String = json["name"].stringValue
1
2
//如果不是数组或者空,返回 []
let list: Array<JSON> = json["list"].arrayValue
1
2
//如果不是字典或者空,返回 [:]
let user: Dictionary<String, JSON> = json["user"].dictionaryValue
setter
1
2
json["name"] = JSON("new-name")
json[0] = JSON(1)
1
2
3
4
5
json["id"].int = 1234567890
json["coordinate"].double = 9766.766
json["name"].string = "jack"
json.arrayObject = [1, 2, 3, 4]
json.dictionaryObject = ["name" : "Jack", "age" : 25]
元对象
1
let jsonObject: Any = json.object
1
if let jsonObject: Any = json.rawValue
1
2
3
4
//把 JSON 转化为字符串元
if let data = json.rawData() {
//做你想做的事情
}
1
2
3
4
//把 字符串元转化为 JSON
if let string = json.rawString() {
//做你想做的事情
}
存在性
1
2
//用来显示 JSON 中是否有指定的值
if json["name"].exist()
文字转换

更多关于文字转换的信息:Swift Literal Convertibles

1
2
//字符串转换
let json: JSON = "I'm a json"
1
2
//整型转换
let json: JSON = 1234
1
2
//Bool型转换
let json: JSON = true
1
2
//单精度浮点数转换
let json: JSON = 2.8756
1
2
//字典转换
let json: JSON = ["I" : "am", "a" : "json"]
1
2
//数组转换
let json: JSON = ["I", "am", "a", "json"]
1
2
//空转换
let json: JSON = nil
1
2
3
4
5
6
//带有下标的数组
var json: JSON = [1, 2, 3]
json[0] = 100
json[1] = 200
json[3] = 300
json[999] = 300 //别担心, 什么都不会发生
1
2
3
4
5
6
//带有下标的字典
var json: JSON = ["name" : "Jack", "age" : 25, "list" : ["a", "b", "c", ["what" : "this"]]]
json["list"][3]["what"] = "that"
json["list", 3, "what"] = "that"
let path: [JSONSubscriptType] = ["list", 3, "what"]
jaon[path] = "that"
1
2
3
4
5
6
//带有其他的 JSON 对象
let user: JSON = ["username" : "Strve", "password" : "supersecurepassword"]
let auth: JSON = [
"user": user.object //使用 user.object 替代 user
"apikey": "supersecuretapitoken"
]
合并

把一个 JSON 与另外一个 JSON 合并是可能的。合并两个 JSON 会把原始 JSON 中不存在的只出现在另外一个 JSON 中的数据添加进来。

如果两个 JSON 包含了的值有相同的键,通常情况下会重写原JSON的值,但是有两种情况下会有特别的处理:

  • 在两个值都是JSON.Type.array 的情况下,值形成在另一个JSON中的数组,附加到原始JSON的数组值。
  • 在两个值都是 JSON.Type.dictionary 的情况下,两个JSON值都以合并封装JSON的相同方式合并。

在JSON中的两个字段具有不同类型的情况下,值将始终被覆盖。

有两种不同的方式合并: merge 修改原始的 JSON ,而合并在副本上以非破坏性方式工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
let original: JSON = [
"first_name": "John",
"age": 20,
"skills": ["Coding", "Reading"],
"address": [
"street": "Front St",
"zip": "12345",
]
]

let update: JSON = [
"last_name": "Doe",
"age": 21,
"skills": ["Writing"],
"address": [
"zip": "12342",
"city": "New York City"
]
]

let updated = original.merge(with: update)
// [
// "first_name": "John",
// "last_name": "Doe",
// "age": 21,
// "skills": ["Coding", "Reading", "Writing"],
// "address": [
// "street": "Front St",
// "zip": "12342",
// "city": "New York City"
// ]
// ]
文字表示

有两种可选可以用:

  • 使用 Swift 默认的
  • 使用一个自定义的,可以很好地处理可选项,并将 nil 表示为 “null” :
1
2
3
4
let dict = ["1":2, "2":"two", "3": nil] as [String: Any?]
let json = JSON(dict)
let representation = json.rawString(options: [.castNilToNSNull: true])
// representation is "{\"1\":2,\"2\":\"two\",\"3\":null}", which represents {"1":2,"2":"two","3":null}

和 Alamofire 一起使用

SWiftyJSON 很好地包装了 Alamofire JSON 相应的结果:

1
2
3
4
5
6
7
8
9
10
Alamofire.request(url, mothod: .get).validate().responseJSON {
response in
switch response.result {
case .success(let value):
let json = JSON(value)
print("JSON:\(json)")
case .failure(let error):
print(error)
}
}
Newer Post

毕业了,完结撒花

毕业感想一眨眼就毕业了,内心感慨万千,总的来说还是不错的,收获了很多朋友,挺铁的朋友,这是一种无形的财富吧(狗富贵,勿相汪)。说到我自己,大学学到的东西其实不是很多,原因嘛。。。。 大多都是自学的比如iOS、PHP 但是学的都不怎么样,也就是也表面的东西,懂得如何使用三方库,会用API。。对于技术 …

杂谈 继续阅读
Older Post

总结Ubuntu下部署LNMP环境

主要还是对于整个服务器如何配置做一个整理。(本人菜鸡。。如有不对,请指出。。勿喷) …

后端探索 继续阅读